﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UnrealDebugger
{
    // Commands (Communication from IDE to UDK)

    partial class UnrealDebuggerIDE
    {
        private string _activeCommand = null;
        public string ActiveCommand { get { return _activeCommand; } }
        public void UDKRespondedToActiveCommand() { _activeCommand = null; }
        public bool IsWaitingForUDKResponse() { return _activeCommand != null; }

        public delegate void CommandDelegate(string command);
        public event CommandDelegate OnCommand;

        protected bool CanRaiseCommandEvents()
        {
            return OnCommand != null && !IsWaitingForUDKResponse();
        }

        protected virtual bool RaiseCommandEvent(string command, bool needsResponseFromUDK)
        {
            if (CanRaiseCommandEvents())
            {
                if (needsResponseFromUDK) 
                { 
                    string[] tokens = command.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                    this._activeCommand = tokens.Length > 0 ? tokens[0] : null;
                }

                this._commandPanel.AddLineToLog(command);
                OnCommand(command);
                return true;
            }

            return false;
        }

        public class Commands
        {
            public static bool Execute(string command)
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;
                return ide.RaiseCommandEvent(command, false);
            }

            public static bool ChangeStack(int pos)
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;
                ide._activeCallstackPosition = pos;

                return ide.RaiseCommandEvent(string.Format("changestack {0}", pos), true);
            }

            public static bool Go()
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;

                bool attached = UnrealDebuggerIDE.Instance.ActiveCallstackDepth > 0;
                bool result = attached && ide.RaiseCommandEvent("go", false);

                if (result)
                {
                    ide.DetachDebugger();
                }

                return result;
            }

            public static bool Break()
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;

                bool attached = UnrealDebuggerIDE.Instance.ActiveCallstackDepth > 0;

                if (!attached && ide._breakCount == 0) { ide._breakCount++; }
              
                bool result = !attached && ide.RaiseCommandEvent("break", true);
                return result;
            }

            public static bool StepInto()
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;

                bool attached = UnrealDebuggerIDE.Instance.ActiveCallstackDepth > 0;
                bool result = attached && ide.RaiseCommandEvent("stepinto", true);
                return result;
            }

            public static bool StepOver()
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;

                bool attached = UnrealDebuggerIDE.Instance.ActiveCallstackDepth > 0;
                bool result = attached && ide.RaiseCommandEvent("stepover", true);
                return result;
            }

            public static bool StepOut()
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;

                bool attached = UnrealDebuggerIDE.Instance.ActiveCallstackDepth > 0;
                bool resume = UnrealDebuggerIDE.Instance.ActiveCallstackDepth <= 1;
                bool result = attached && ide.RaiseCommandEvent("stepoutof", resume ? false : true);

                if (result && resume)
                {
                    ide.DetachDebugger();
                }

                return result;
            }

            public static bool ConnectBreakpoint(string className, int lineNo)
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;
                if (ide.CanRaiseCommandEvents())
                {
                    ide._project.AddBreakpoint(className, lineNo);
                    return ide.RaiseCommandEvent("addbreakpoint " + className + " " + lineNo.ToString(), false);
                }

                return false;                
            }

            public static bool DisconnectBreakpoint(string className, int lineNo)
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;

                if (ide.CanRaiseCommandEvents())
                {
                    bool result = ide.RaiseCommandEvent("removebreakpoint " + className + " " + lineNo.ToString(), false);
                    ide._project.RemoveBreakpoint(className, lineNo);
                    return result;
                }

                return false;
            }

            public static bool AddWatch(string varname)
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;
                return ide.RaiseCommandEvent("addwatch " + varname, false);
            }

            public static bool RemoveWatch(string varname)
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;
                return ide.RaiseCommandEvent("removewatch " + varname, false);
            }

            public static bool ClearWatches()
            {
                UnrealDebuggerIDE ide = UnrealDebuggerIDE.Instance;
                return ide.RaiseCommandEvent("clearwatch", false);
            }
        }
    }
}
